package exsun.jt808.data.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.ParseException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.*;

/**
 * 提供通过HTTP协议获取内容的方法
 * 
 * 所有提供方法中的params参数在内部不会进行自动的url encode，如果提交参数需要进行url encode，请调用方自行处理
 * 
 * @Description: HTTP请求代理工具
 * @author houzw
 */
public class HttpUtil {
	/**
	 * 支持的Http method
	 * 
	 */
	private static enum HttpMethod {
		POST, DELETE, GET, PUT, HEAD;
	}
	public static String post(String url , JSONObject json ) {
		Map<String, String> data = new HashMap<String, String>();
		for (Object key : json.keySet()) {
			data.put(key.toString(), json.get(key.toString()).toString());
		}
		return post(url, data);
	}

	public static String post(String url , Map<String, ? extends Object > data) {
		CloseableHttpClient client = HttpClients.createDefault();
		HttpPost httpPost = new HttpPost();
		try {
			httpPost.setURI(new URI(url));
			if(data != null){
				List<NameValuePair> params = new ArrayList<NameValuePair>();
				for (String key : data.keySet()) {
					params.add(new BasicNameValuePair(key, data.get(key).toString()));
				}
				httpPost.setEntity(new UrlEncodedFormEntity(params,"utf-8"));
			}

			RequestConfig config = RequestConfig.custom()
					.setConnectTimeout(1000)
					.setConnectionRequestTimeout(2000)
					.build();
			httpPost.setConfig(config);
			CloseableHttpResponse response = client.execute(httpPost);
			HttpEntity entity = response.getEntity();
			if(entity == null) return null;
			BufferedReader reader = new BufferedReader((new InputStreamReader(entity.getContent(),"utf-8")));
			String str = null;
			StringBuffer buffer = new StringBuffer();
			while ( (str = reader.readLine()) != null ) {
				buffer.append(str);
			}
			response.close();
			return buffer.toString();
		} catch (URISyntaxException | IOException e) {
			return null;
		} finally {
			try {
				client.close();
			} catch (IOException e) {
			}
		}
	}

	private static String invokeUrl(String url, String params, Map<String, String> headers, int connectTimeout, int readTimeout, String encoding, HttpMethod method) {
		// 只有POST方法才能通过OutputStream(即form的形式)提交参数
		if (method != HttpMethod.POST) {
			if (params.indexOf('=') != -1) {
				url += "?" + params;
			} else {
				url += params;
			}
		}
		URL uUrl = null;
		HttpURLConnection conn = null;
		BufferedWriter out = null;
		BufferedReader in = null;
		try {
			uUrl = new URL(url);
			conn = (HttpURLConnection) uUrl.openConnection();
			conn.addRequestProperty("content-type", "application/json");
			conn.setRequestMethod(method.toString());
			conn.setDoInput(true);
			conn.setDoOutput(true);
			// 设置连接超时时间
			conn.setConnectTimeout(connectTimeout);
			// 设置读取超时时间
			conn.setReadTimeout(readTimeout);
			// 指定请求header参数
			if (headers != null && headers.size() > 0) {
				Set<String> headerSet = headers.keySet();
				for (String key : headerSet) {
					conn.setRequestProperty(key, headers.get(key));
				}
			}

			if (params != null && method == HttpMethod.POST) {
				// 发送请求参数
				out = new BufferedWriter(new OutputStreamWriter(conn.getOutputStream(), encoding));
				out.write(params);
				out.flush();
			}

			// 接收返回结果
			StringBuilder result = new StringBuilder();
			in = new BufferedReader(new InputStreamReader(conn.getInputStream(), encoding));
			if (in != null) {
				String line = "";
				while ((line = in.readLine()) != null) {
					result.append(line);
				}
			}
			return result.toString().replace("null", "\"\"");// 把null转成空字符串
		} catch (Exception e) {
			e.printStackTrace();
			System.err.println("调用接口[" + url + "]失败!参数:" + params);
			// 处理错误流，提高http连接被重用的几率
			try {
				byte[] buf = new byte[100];
				InputStream es = conn.getErrorStream();
				if (es != null) {
					while (es.read(buf) > 0) {
						es.close();
					}
				}
			} catch (Exception el) {
				el.printStackTrace();
			}
		} finally {
			try {
				if (out != null) {
					out.close();
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
			try {
				if (in != null) {
					in.close();
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
			// 关闭连接
			if (conn != null) {
				conn.disconnect();
			}
		}
		return null;
	}

	public static String sendPostByUrlEncoder(String url,Map<String, String> map){
		List<NameValuePair> params=new ArrayList<NameValuePair>();
		for(Map.Entry<String, String> entry : map.entrySet()){
			params.add(new BasicNameValuePair(entry.getKey(),entry.getValue()));
		}
		HttpPost httppost = new HttpPost(url);
		httppost.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
		HttpResponse response = null;
		try {
			httppost.setEntity(new UrlEncodedFormEntity(params,"UTF-8"));
			HttpClient httpClient = HttpClientBuilder.create().build();
			response = httpClient.execute(httppost);
		} catch (IOException e) {
			e.printStackTrace();
		}
		HttpEntity httpEntity = response.getEntity();
		String result = null;
		try {
			result = EntityUtils.toString(httpEntity);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return result;
	}


	/**
	 * POST方法提交Http请求，语义为"增加" <br/>
	 * 注意：Http方法中只有POST方法才能使用body来提交内容
	 * 
	 * @return
	 */
	public static String post(String url, String params, int connectTimeout, int readTimeout, String charset) {
		return invokeUrl(url, params, null, connectTimeout, readTimeout, charset, HttpMethod.POST);
	}


	/**
	 * 发送post请求
	 * @param url  路径
	 * @param json json字符串
	 * @param encoding 编码格式
	 * @return
	 * @throws ParseException
	 * @throws IOException
	 */
	public static String send(String url, String json,String encoding) throws ParseException, IOException{
		String body = "";

		//创建httpclient对象
		CloseableHttpClient client = HttpClients.createDefault();
		//创建post方式请求对象
		HttpPost httpPost = new HttpPost(url);


		RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(3000)
				.setSocketTimeout(3000).setConnectTimeout(3000).build();
		httpPost.setConfig(requestConfig);

		//装填参数
		StringEntity s = new StringEntity(json, "utf-8");
		s.setContentEncoding(new BasicHeader(HTTP.CONTENT_TYPE, "application/json"));
		//设置参数到请求对象中
		httpPost.setEntity(s);
		System.out.println("请求地址："+url);
//        System.out.println("请求参数："+nvps.toString());

		//设置header信息
		//指定报文头【Content-type】、【User-Agent】
//        httpPost.setHeader("Content-type", "application/x-www-form-urlencoded");
		httpPost.setHeader("Content-type", "application/json");
//		httpPost.setHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");

		//执行请求操作，并拿到结果（同步阻塞）
		CloseableHttpResponse response = client.execute(httpPost);
		//获取结果实体
		HttpEntity entity = response.getEntity();
		if (entity != null) {
			//按指定编码转换结果实体为String类型
			body = EntityUtils.toString(entity, encoding);
		}
		EntityUtils.consume(entity);
		//释放链接
		response.close();
		return body;
	}
	/**
	 * POST方法提交Http请求，语义为"增加" <br/>
	 * 注意：Http方法中只有POST方法才能使用body来提交内容
	 * 
	 * @return
	 */
	public static String sendPost(String url, String params, int connectTimeout, int readTimeout, String charset) {
		Map<String, String> headers = new HashMap<String, String>();
		headers.put("Content-Type", "application/json");
		return invokeUrl(url, params, headers, connectTimeout, readTimeout, charset, HttpMethod.POST);
	}

	/**
	 * GET方法提交Http请求，语义为"查询"
	 * 
	 * @return
	 */
	public static String get(String url, String params, int connectTimeout, int readTimeout, String charset) {
		return invokeUrl(url, params, null, connectTimeout, readTimeout, charset, HttpMethod.GET);
	}

	/**
	 * GET方法提交Http请求，语义为"查询"
	 * 
	 * @return
	 */
	public static String get(String url, String params, Map<String, String> headers, int connectTimeout, int readTimeout, String charset) {
		return invokeUrl(url, params, headers, connectTimeout, readTimeout, charset, HttpMethod.GET);
	}

	/**
	 * PUT方法提交Http请求，语义为"更改"<br/>
	 * 注意：PUT方法也是使用url提交参数内容而非body，所以参数最大长度收到服务器端实现的限制，Resin大概是8K
	 * 
	 * @return
	 */
	public static String put(String url, String params, int connectTimeout, int readTimeout, String charset) {
		return invokeUrl(url, params, null, connectTimeout, readTimeout, charset, HttpMethod.PUT);
	}

	/**
	 * PUT方法提交Http请求，语义为"更改" <br/>
	 * 注意：PUT方法也是使用url提交参数内容而非body，所以参数最大长度收到服务器端实现的限制，Resin大概是8K
	 */
	public static String put(String url, String params, Map<String, String> headers, int connectTimeout, int readTimeout, String charset) {
		return invokeUrl(url, params, headers, connectTimeout, readTimeout, charset, HttpMethod.PUT);
	}

	/**
	 * DELETE方法提交Http请求，语义为"删除"
	 */
	public static String delete(String url, String params, int connectTimeout, int readTimeout, String charset) {
		return invokeUrl(url, params, null, connectTimeout, readTimeout, charset, HttpMethod.DELETE);
	}

	public static String delete(String url, String params, Map<String, String> headers, int connectTimeout, int readTimeout, String charset) {
		return invokeUrl(url, params, headers, connectTimeout, readTimeout, charset, HttpMethod.DELETE);
	}

	public static String head(String url, String params, int connectTimeout, int readTimeout, String charset) {
		return invokeUrl(url, params, null, connectTimeout, readTimeout, charset, HttpMethod.HEAD);
	}

	public static String head(String url, String params, Map<String, String> headers, int connectTimeout, int readTimeout, String charset) {
		return invokeUrl(url, params, headers, connectTimeout, readTimeout, charset, HttpMethod.HEAD);
	}

	/**
	 * 将Map分割
	 * 
	 * @param paramMap
	 * @return String
	 */
	public static String prepareParam(Map<String, Object> paramMap) {
		if (paramMap == null || paramMap.isEmpty()) {
			return null;
		} else {
			StringBuffer sb = new StringBuffer();
			for (String key : paramMap.keySet()) {
				if (sb.length() < 1) {
					sb.append(key).append("=");
				} else {
					sb.append("&").append(key).append("=");
				}
				if (paramMap.get(key) != null) {
					String value = paramMap.get(key).toString();
					sb.append(value);
				}
			}
			return sb.toString();
		}
	}

	/**
	 * 将Map分割成 例如—id-name
	 */
	public static String Param(Map<String, Object> paramMap) {
		if (paramMap == null || paramMap.isEmpty()) {
			return null;
		} else {
			StringBuffer sb = new StringBuffer();
			for (String key : paramMap.keySet()) {
				if (paramMap.get(key) != null) {
					String value = paramMap.get(key).toString();
					if (sb.length() < 1) {
						sb.append("-").append(value);
					} else {
						sb.append("-").append(value);
					}
				}
			}
			return sb.toString();
		}
	}

	public static void main(String[] args) {
		sendPost("http://120.221.95.146:10005/api/Distribute/HisVideoClose?phoneStr=040575298960&logicChannelNo=3","",
				3000,3000,"UTF-8");
		// --------------geo接口测试----post---------------------
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("longitude", 116.818873);
		map.put("latitude", 40.27537);
		map.put("distance", 10);
		map.put("unit", "km");
		map.put("asc", true);
		String param = HttpUtil.prepareParam(map);
		param = JSONObject.toJSONString(map);
		String url = "http://192.168.180.123:8089/iis/dynamic/vehicleposition/get_vehicle_area";
		String result = HttpUtil.sendPost(url, param, 30000, 30000, "UTF-8");
		JSONObject json = JSONObject.parseObject(result);
		System.out.println(json);
	}
}
